/*
 *    Copyright (c) 2018-2025, cloud All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: cloud
 */
package com.fuyao.cloud.space.regional.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyao.cloud.common.core.constant.CommonConstants;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.data.datascope.DataScope;
import com.fuyao.cloud.common.data.resolver.NumberResolver;
import com.fuyao.cloud.common.excel.vo.ErrorMessage;
import com.fuyao.cloud.space.constant.RegionalConstant;
import com.fuyao.cloud.space.edifice.mapper.RoomEdificeMapper;
import com.fuyao.cloud.space.entity.RoomEdifice;
import com.fuyao.cloud.space.entity.RoomLand;
import com.fuyao.cloud.space.entity.RoomRegional;
import com.fuyao.cloud.space.regional.mapper.RoomRegionalMapper;
import com.fuyao.cloud.space.regional.service.RoomRegionalService;
import com.fuyao.cloud.space.roomland.mapper.RoomLandMapper;
import com.fuyao.cloud.space.vo.ExcelImportRegionalVO;
import com.fuyao.cloud.space.vo.ExcelRegionalVO;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 区域管理
 *
 * @author liyue
 * @date 2021-11-09 15:09:42
 */
@Service
@AllArgsConstructor
public class RoomRegionalServiceImpl extends ServiceImpl<RoomRegionalMapper, RoomRegional> implements RoomRegionalService {

    private final RoomRegionalMapper fyRoomRegionalMapper;
    private final RoomLandMapper fyRoomLandMapper;
    private final RoomEdificeMapper edificeMapper;

    @Override
    public boolean save(RoomRegional entity) {
        beforeSave(entity);
        return super.save(entity);
    }

    @Override
    public boolean updateById(RoomRegional entity) {
        beforeSave(entity);
        return super.updateById(entity);
    }

    /**
     * 查询全部部门树
     *
     * @return 树
     */
    @Override
    public List<Tree<Long>> selectTree() {
        // 查询空间信息
        List<RoomRegional> roomRegionalList = fyRoomRegionalMapper.selectList(Wrappers.emptyWrapper());
        // 查询数据权限内空间信息
        List<Long> regionalOwnIdList = fyRoomRegionalMapper.selectListByScope(Wrappers.emptyWrapper(), new DataScope()).stream()
                .map(RoomRegional::getDeptId).collect(Collectors.toList());

        // 权限内空间信息
        List<TreeNode<Long>> collect = roomRegionalList.stream()
                .sorted(Comparator.comparing(RoomRegional::getCreateTime)).map(regional -> {
                    TreeNode<Long> treeNode = new TreeNode();
                    treeNode.setId(regional.getId());
                    treeNode.setParentId(regional.getParentId());
                    treeNode.setName(regional.getName());
                    treeNode.setWeight(regional.getOrdernumber());
                    // 有权限不返回标识
                    Map<String, Object> extra = new HashMap<>(8);
                    extra.put("isLock", !regionalOwnIdList.contains(regional.getDeptId()));
                    extra.put("createTime", regional.getCreateTime());
                    treeNode.setExtra(extra);
                    return treeNode;
                }).collect(Collectors.toList());

        return TreeUtil.build(collect, 0L);
    }

    @Override
    public List<Tree<Long>> selectLandTree() {
        // 查询土地信息
        List<RoomLand> roomLandList = fyRoomLandMapper.selectList(Wrappers.emptyWrapper());
        // 查询数据权限内空间信息
        List<Long> regionalOwnIdList = fyRoomLandMapper.selectListByScope(Wrappers.emptyWrapper(), new DataScope()).stream()
                .map(RoomLand::getDeptId).collect(Collectors.toList());
        // 权限内地土地信息
        List<TreeNode<Long>> collect = roomLandList.stream()
                .sorted(Comparator.comparingLong(RoomLand::getId)).map(land -> {
                    TreeNode<Long> treeNode = new TreeNode();
                    treeNode.setId(land.getId());
                    treeNode.setParentId(0L);
                    treeNode.setName(land.getAssetName());
                    treeNode.setWeight(120);
                    // 有权限不返回标识
                    Map<String, Object> extra = new HashMap<>(8);
                    extra.put("isLock", !regionalOwnIdList.contains(land.getDeptId()));
                    extra.put("createTime", land.getCreateTime());
                    treeNode.setExtra(extra);
                    return treeNode;
                }).collect(Collectors.toList());
        return TreeUtil.build(collect, 0L);
    }

    public List<ExcelRegionalVO> listRegional(RoomRegional fyRoomRegional) {
        // 根据数据权限查询全部的用户信息
        List<RoomRegional> regionalList = baseMapper.selectListByScope(Wrappers.emptyWrapper(), new DataScope());
        // 转换成execl 对象输出
        return regionalList.stream().map(regional -> {
            ExcelRegionalVO excelVO = new ExcelRegionalVO();
            BeanUtils.copyProperties(regional, excelVO);
            return excelVO;
        }).collect(Collectors.toList());
    }

    @Override
    public R importRegional(List<ExcelImportRegionalVO> excelVOList, BindingResult bindingResult) {
        // 通用校验获取失败的数据
        List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();
        // 个性化校验逻辑
        List<RoomRegional> regionalList = this.list();
        List<RoomLand> roomLandList = fyRoomLandMapper.selectList(Wrappers.emptyWrapper());

        if (excelVOList != null && excelVOList.isEmpty()) {
            assert errorMessageList != null;
            errorMessageList.add(new ErrorMessage("无数据导入"));
            return R.failed(errorMessageList);
        }
        // 执行数据插入操作 组装 FyRoomRegional
        for (int i = 0; i < excelVOList.size(); i++) {
            ExcelImportRegionalVO excel = excelVOList.get(i);
            Set<String> errorMsg = new HashSet<>();

            if(StrUtil.isNotEmpty(excel.getCode())){
                // 校验编码是否存在
                boolean exsitCode = regionalList.stream()
                        .anyMatch(regional -> regional.getCode().equals(excel.getCode()));

                if (exsitCode) {
                    errorMsg.add(String.format("%s 编码已存在 %s ", excel.getCode(), "，"));
                }
            }
            RoomRegional fyRoomRegional = new RoomRegional();
            BeanUtils.copyProperties(excel, fyRoomRegional);

            // 验证父区域编码
            if (!StrUtil.isEmpty(excel.getParentCode())) {
                Optional<RoomRegional> roomRegionalOptional = regionalList.stream().
                        filter(regional -> regional.getCode().equals(excel.getParentCode())).findFirst();
                if (roomRegionalOptional.isPresent()) {
                    RoomRegional roomRegional = roomRegionalOptional.get();
                    fyRoomRegional.setParentId(roomRegional.getId());
                    fyRoomRegional.setParentName(roomRegional.getName());
                }
            }

            // 验证土地资产编码
            if (!StrUtil.isEmpty(excel.getAssetNumber())) {
                Optional<RoomLand> landOptional = roomLandList.stream().
                        filter(land -> land.getAssetNumber().equals(excel.getAssetNumber())).findFirst();
                if (landOptional.isPresent()) {
                    RoomLand land = landOptional.get();
                    fyRoomRegional.setLandId(land.getId());
                    fyRoomRegional.setLandName(land.getAssetName());
                }
            }

            // 数据合法情况
            if (CollUtil.isEmpty(errorMsg)) {
                insertExcelRegional(excel, fyRoomRegional);
            } else {
                // 数据不合法情况
                errorMessageList.add(new ErrorMessage((long) (i + 1), errorMsg));
            }
        }
        if (CollUtil.isNotEmpty(errorMessageList)) {
            return R.failed(errorMessageList);
        }
        return R.ok();
    }

    @Override
    public List<RoomRegional> getByCode(String code) {
        return this.baseMapper.selectList(Wrappers.<RoomRegional>query().lambda().eq(RoomRegional::getCode, code));
    }

    @Override
    public List<RoomRegional> listByRoomLandId(List<Long> roomLandIds) {
        LambdaQueryWrapper<RoomRegional> queryWrapper = Wrappers.<RoomRegional>lambdaQuery().in(RoomRegional::getLandId, roomLandIds);
        return this.list(queryWrapper);
    }

    @Override
    public List<RoomRegional> getByParentId(Serializable id) {
        LambdaQueryWrapper<RoomRegional> queryWrapper = Wrappers.<RoomRegional>lambdaQuery().eq(RoomRegional::getParentId, id);
        return this.list(queryWrapper);
    }

    @Override
    public R batchDelete(List<Long> ids) {
        LambdaQueryWrapper<RoomRegional> queryWrapper = Wrappers.<RoomRegional>lambdaQuery().in(RoomRegional::getParentId, ids);
        long regionalCount = this.count(queryWrapper);
        Assert.isTrue((regionalCount == 0), "删除区域信息包含子集数据，请先删除子集数据，再删除父级数据");

        long count = edificeMapper.selectCount(Wrappers.<RoomEdifice>lambdaQuery().in(RoomEdifice::getRegionalId, ids));
        Assert.isTrue((count == 0), "删除区域信息关联楼栋信息，请先删除关联楼栋信息数据后，再删除区域数据");

        boolean remove = this.removeByIds(ids);
        if (remove) {
            return R.ok(CommonConstants.SUCCESS, String.format("成功删除%s条数据", ids.size()));
        }
        return R.failed("删除失败");
    }

    /**
     * 保存导入信息
     *
     * @param excel          导入对象
     * @param fyRoomRegional 添加对象
     */
    private void insertExcelRegional(ExcelImportRegionalVO excel, RoomRegional fyRoomRegional) {
        this.beforeSave(fyRoomRegional);
        super.save(fyRoomRegional);
    }

    @Override
    public boolean removeById(Serializable id) {
        Assert.isTrue(CollUtil.isEmpty(getByParentId(id)), "该区域信息包含子集数据，请选删除子集数据，再删除父级数据");
        LambdaQueryWrapper<RoomEdifice> queryWrapper = Wrappers.<RoomEdifice>lambdaQuery().eq(RoomEdifice::getRegionalId, id);
        long count = edificeMapper.selectCount(queryWrapper);
        Assert.isTrue((count <= 0), "该区域信息关联楼栋信息，请选删除关联楼栋信息数据后，再删除区域数据");
        return super.removeById(id);
    }

    /**
     * 补充属性值
     *
     * @param entity 区域对象
     */
    private void beforeSave(RoomRegional entity) {
        entity.setUnid((StrUtil.isEmpty(entity.getUnid()) ? UUID.fastUUID().toString() : entity.getUnid()));
        if (StrUtil.isEmpty(entity.getCode())) {
            String numberStr = NumberResolver.getNumberStr(RegionalConstant.REGIONAL_TYPE, RegionalConstant.REGIONAL_CODE).getData();
            entity.setCode(numberStr);
        }
        if (entity.getOrdernumber() == null || entity.getOrdernumber() == 0) {
            entity.setOrdernumber(NumberResolver.getNumberValue(RegionalConstant.REGIONAL_TYPE, RegionalConstant.REGIONAL_CODE).getData().intValue());
        }
        if (ObjectUtils.isNotNull(entity.getParentId()) && entity.getParentId() > 0) {
            RoomRegional parent = this.getById(entity.getParentId());
            entity.setParentName(parent.getName());
            String fullcode = parent.getFullcode();
            String fullname = parent.getFullname();
            entity.setParentCode(fullcode);
            entity.setFullcode(fullcode + "." + entity.getCode());
            entity.setFullcode(fullname + "." + entity.getName());
            int level = parent.getLevel();
            entity.setLevel(level + 1);
            // dataCode
            entity.setDataCode(parent.getDataCode() + "." + entity.getCode());
        } else {
            entity.setFullname(entity.getName());
            entity.setFullcode(entity.getCode());
            entity.setLevel(RegionalConstant.START_LEVEL);
            entity.setDataCode(entity.getFullcode());
        }
        // 关联土地
        if (ObjectUtils.isNotNull(entity.getLandId()) && entity.getLandId() > 0) {
            RoomLand fyRoomLand = this.fyRoomLandMapper.selectById(entity.getLandId());
            entity.setLandName(fyRoomLand.getAssetName());
            entity.setLandId(fyRoomLand.getId());
        }
    }
}
